// const { functionsIn } = require("lodash")

// 2.1 promise有三个状态
const PENDING = 'pending' // 等待
const FULLFILLED = 'fullfilled' // 成功
const REJECTED = 'rejected' // 失败


// 1. promise是一个类, 执行类需要传递构造函数并立即执行
class myPromise {
  constructor(executor) { // 构造函数constructor是一个类必须要有的方法，默认返回实例对象
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  status = PENDING; // 状态
  value = undefined; // 成功的值默认是没有的是undefined
  reason = undefined; // 失败的值默认是没有的是undefined
  successCallback = [];
  fallCallback = [];
  resolve = (value) => {
    // 2.2 如果状态不是等待，阻止程序向下执行（因为Promise有三个状态，只能 pending -> fullfilled / pending -> rejected, 一旦状态确定就不可改变）
    if (this.status !== PENDING) return;
    this.status = FULLFILLED  // 更改状态为成功
    this.value = value // 保存成功的值
    // 5.2 判断成功回调函数是否存在，存在调用
    // this.successCallback && this.successCallback(this.value)
    // while (this.successCallback.length) this.successCallback.shift()(this.value)
    while (this.successCallback.length) this.successCallback.shift()()
  } // 箭头函数让函数内部指向类
  reject = (reason) => {
    // 2.3 如果状态不是等待，阻止程序向下执行（因为Promise有三个状态，只能 pending -> fullfilled / pending -> rejected, 一旦状态确定就不可改变）
    if (this.status !== PENDING) return;
    this.status = REJECTED // 更改状态为失败
    this.reason = reason // 保存失败的原因
    // 5.2 判断失败回调函数是否存在，存在调用
    // this.fallCallback && this.fallCallback(this.reason)
    // while (this.fallCallback.length) this.fallCallback.shift()(this.reason)
    while (this.fallCallback.length) this.fallCallback.shift()()
  }
  then (successCallback, fallCallback) {
    successCallback = successCallback ? successCallback : value => value
    fallCallback = fallCallback ? fallCallback : reason => { throw reason }
    
    // 11. 传递
    console.log('this.status', this.status)
    // 返回promise对象可进行链式调用，并在把上一个then传给下一个then
    let promise2 = new myPromise((resolve, reject) => {
      // 3. then方法内部就是判断状态的，状态是成功调用成功回调，失败调用失败回调
      if (this.status === FULLFILLED) {
        // 9.2 同步代码执行后就可以拿到promise
        setTimeout(() => {
          try {
            // 4.1 then成功的回调有一个参数，表示成功的值（默认是空的，就是undefined）
            let x = successCallback(this.value)
            // 判断x的值是普通值还是promise对象
            // 如果是普通值直接resolve
            // 如果是promise对象则查看返回的结果，根据这个结果决定调用resolve还是reject
            // resolve(x)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        // 4.2 then失败的回调有一个参数，表示失败的原因
        // fallCallback(this.reason)
        // let y = fallCallback(this.reason)
        // reject(y)
        setTimeout(() => {
          try {
            // 4.1 then成功的回调有一个参数，表示成功的值（默认是空的，就是undefined）
            let x = fallCallback(this.reason)
            // 判断x的值是普通值还是promise对象
            // 如果是普通值直接resolve
            // 如果是promise对象则查看返回的结果，根据这个结果决定调用resolve还是reject
            // resolve(x)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else {
        // 等待状态
        // 5.1  将成功和失败的状态存储起来
        // this.successCallback = successCallback
        // this.fallCallback = fallCallback
        // this.successCallback.push(successCallback)
        // this.fallCallback.push(fallCallback)
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              // 4.1 then成功的回调有一个参数，表示成功的值（默认是空的，就是undefined）
              let x = successCallback(this.value)
              // 判断x的值是普通值还是promise对象
              // 如果是普通值直接resolve
              // 如果是promise对象则查看返回的结果，根据这个结果决定调用resolve还是reject
              // resolve(x)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        this.fallCallback.push(() => {
          setTimeout(() => {
            try {
              // 4.1 then成功的回调有一个参数，表示成功的值（默认是空的，就是undefined）
              let x = fallCallback(this.reason)
              // 判断x的值是普通值还是promise对象
              // 如果是普通值直接resolve
              // 如果是promise对象则查看返回的结果，根据这个结果决定调用resolve还是reject
              // resolve(x)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
      }
    })
    return promise2
  }
  finally (callback) {
    return this.then((value) => {
      // callback()
      // return value
      return myPromise.resolve(callback()).then(() => value)
    }, (reason) => {
      // callback()
      // // throw reason ???为什么我这么不会执行到finally后面的then
      // return reason
      return myPromise.resolve(callback()).then(() => { throw reason })
    })
  }
  catch(fallCallback) {
    return this.then(undefined, fallCallback)
  }
  static all (array) {
    // 如果是promise保存结果，如果是普通值也保存下来，最后一并返回
    let result = []
    let index = 0
    console.log('all')
    return new myPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value
        index++
        if (index === array.length) {
          resolve(result)
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i]
        if (current instanceof myPromise) {
          // promise 对象
          current.then(value => addData(i, value), reason => reject(reason))
        } else {
          // 普通值
          addData(i, array[i])
        }
      }
    })
  }
  static resolve (value) {
    if(value instanceof myPromise) return value
    return new myPromise(resolve => resolve(value))
  }

}

function resolvePromise (promise2, x, resolve, reject) {
  if (promise2 === x) {
    // 9.1 避免then中同一个promise循环返回
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof myPromise) {
    // x.then((value) => {resolve(value)}, reason => reject(reason))
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

// 在node中
module.exports = myPromise
// 在es6中
// export const myPromise = myPromise
